/*
Copyright (C) 2010  Christoph Schnack, Berlin (Germany)

This file is part of Tribuit.

    Tribuit is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Tribuit is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Tribuit.  If not, see <http://www.gnu.org/licenses/>.


########################################################################
*/
package Storage;

import java.util.*;

import GuiTools.GuiTools;
import Settings.Settings;
/**
 * 
 * A Vocabulary contains Words, stored in the variable vcb, which is initialized with null, so all methods should 
 * check, if vcb!=null. Changes on the vocabulary should consider the AUTOSAVE state and save() so.
 * 
 * @author Christoph Schnack
 *
 */
public class Vocabulary{
	public Word[] vcb = null;
	Vector<String> sortedTermClassKeysA = new Vector<String>(),sortedTermClassKeysB = new Vector<String>();
	public HashMap<String,TermClass> tcsA = new HashMap<String,TermClass>();
	public HashMap<String,TermClass> tcsB = new HashMap<String,TermClass>();
	public Vector<String> categoriesA = new Vector<String>(),categoriesB = new Vector<String>();
	private boolean CHANGED = true;
	Storage MAINVOC;
	Settings SET;
	String name,languageA,languageB;
	
	/**
	 * Creates an empty vocabulary.
	 * 
	 * @param name1 1st language's name
	 * @param name2 2nd language's name
	 */
	
	public Vocabulary(String name1,String name2, Storage mainvoc, Settings set,boolean loading){		
		languageA = name1;
		languageB = name2;
		MAINVOC = mainvoc;
		SET = set;
		name = name1+" - "+name2;
		tcsA.put("default",new TermClass());
		tcsB.put("default",new TermClass());
		sortedTermClassKeysA.add("default");
		sortedTermClassKeysB.add("default");
		categoriesA.add("n.a.");
		categoriesB.add("n.a.");
	}
	
	public void setChanged(boolean arg){
		CHANGED = arg;
	}
	public boolean getChanged(){
		return CHANGED;
	}
	
	public void addTermclassA(String name){
		tcsA.put(name,new TermClass());
		CHANGED = true;
	}
	
	public void addTermclassB(String name){
		tcsB.put(name,new TermClass());
		CHANGED = true;
	}
	
	public TermClass getTermclassA(String arg){
		return tcsA.get(arg);
	}
	
	public TermClass getTermclassB(String arg){
		return tcsB.get(arg);
	}
	
	public String[] getTermclassesKeysA(){
		return tcsA.keySet().toArray(new String[tcsA.keySet().size()]);
	}
	
	public String[] getTermclassesKeysB(){
		return tcsB.keySet().toArray(new String[tcsB.keySet().size()]);
	}
	
	public void setTermclasses(HashMap<String,TermClass> a, HashMap<String,TermClass> b){
		tcsA=a;
		tcsB=b;
		CHANGED = true;
	}
	
	public String getTermClassKeysStringA(){
		if(tcsA.isEmpty()) return "";
		StringBuffer sb = new StringBuffer();
		int counter = 0;
		for(String key : getSortedTermClassKeysA()){
			sb.append(key+(counter++<getSortedTermClassKeysA().size()-1?", ":""));
		}
		return sb.toString();
	}
	
	public String getTermClassKeysStringB(){
		if(tcsB.isEmpty()) return "";
		StringBuffer sb = new StringBuffer();
		int counter = 0;
		for(String key : getSortedTermClassKeysB()){
			sb.append(key+(counter++<getSortedTermClassKeysB().size()-1?", ":""));
		}
		return sb.toString();
	}
	
	public String getTermclassesKeysString(){
		StringBuffer sb = new StringBuffer();
		Vector<String> collector = new Vector<String>();
		String[] aKeys = tcsA.keySet().toArray(new String[tcsA.keySet().size()]);
		for(String s : aKeys){
			collector.add(s);
		}
		String[] bKeys = tcsB.keySet().toArray(new String[tcsB.keySet().size()]);
		for(String s : bKeys){
			if(!collector.contains(s))collector.add(s);
		}
		Collections.sort(collector);
		for(int i=0;i<collector.size();i++){
			sb.append(collector.elementAt(i));
			if(i<collector.size()-1)sb.append(", ");
		}
		return sb.toString();
	}
	
	public String[] getTermclassesAll(){
		Vector<String> collector = new Vector<String>();
		for(String s : tcsA.keySet().toArray(new String[tcsA.keySet().size()])){
			collector.add(s);
		}
		for(String s : tcsB.keySet().toArray(new String[tcsB.keySet().size()])){
			if(!collector.contains(s))collector.add(s);
		}
		Collections.sort(collector);
		return collector.toArray(new String[collector.size()]);
	}
	
	public String getTermclassDataString(){
		StringBuffer sb = new StringBuffer();
		for(String s : categoriesA){
			sb.append(s+"<");
		}
		sb.append("=");
		for(String s : categoriesB){
			sb.append(s+"<");
		}
		sb.append("=");
		for(String s : sortedTermClassKeysA){
			sb.append(s+"<");
		}
		sb.append("=");
		for(String s : sortedTermClassKeysB){
			sb.append(s+"<");
		}
		sb.append("=");
		for(String s : this.getTermclassesKeysA()){
			sb.append(s+":");
			TermClass tc = tcsA.get(s);
			String[] tcKeys = tc.getKeys();
			if(tcKeys!=null){
				for(String t : tcKeys){
					sb.append(t+"%");
					Vector<String> vals = tc.getValues(t);
					if(vals!=null){
						for(int i = 0;i<vals.size();i++){
							sb.append(vals.elementAt(i));
							if(i<vals.size()-1)sb.append(",");
						}
					}
					else sb.append("~");
					sb.append(";");
				}
				sb.append(":");
				Vector<String> sk = tc.getSortedKeys();
				for(int i=0;i<sk.size();i++){
					sb.append(sk.elementAt(i));
					if(i<sk.size()-1)sb.append(",");
				}
			}
			else sb.append("~~~");
			sb.append("#");
			if(tc.hasPrefix()){
				sb.append(tc.getPreFixName()+"%");
				Vector<String> pfVal = tc.getPreFixVal();
				if(pfVal!=null){
					for(int i = 0;i<pfVal.size();i++){
						sb.append(pfVal.elementAt(i));
    					if(i<pfVal.size()-1)sb.append(",");
					}
				}
				else{
					sb.append("~");
				}
			}
			else sb.append("~~~");
			sb.append(">");
		}
		sb.append("=");
		for(String s : this.getTermclassesKeysB()){
			sb.append(s+":");
			TermClass tc = tcsB.get(s);
			String[] tcKeys = tc.getKeys();
			if(tcKeys!=null){
				for(String t : tcKeys){
					sb.append(t+"%");
					Vector<String> vals = tc.getValues(t);
					if(vals!=null){
						for(int i = 0;i<vals.size();i++){
							sb.append(vals.elementAt(i));
							if(i<vals.size()-1)sb.append(",");
						}
					}
					else sb.append("~");
					sb.append(";");
				}
				sb.append(":");
				Vector<String> sk = tc.getSortedKeys();
				for(int i=0;i<sk.size();i++){
					sb.append(sk.elementAt(i));
					if(i<sk.size()-1)sb.append(",");
				}
			}
			else sb.append("~~~");
			sb.append("#");
			if(tc.hasPrefix()){
				sb.append(tc.getPreFixName()+"%");
				Vector<String> pfVal = tc.getPreFixVal();
				if(pfVal!=null){
					for(int i = 0;i<pfVal.size();i++){
						sb.append(pfVal.elementAt(i));
    					if(i<pfVal.size()-1)sb.append(",");
					}
				}
				else{
					sb.append("~");
				}
			}
			else sb.append("~~~");
			sb.append(">");
		}
		sb.append("=");
		return sb.toString();
	}
	
	public HashMap<String, TermClass> getTermclassesA(){
		return tcsA;
	}
	
	public HashMap<String, TermClass> getTermclassesB(){
		return tcsB;
	}

	public Vector<String> getCategoriesA(){
		return categoriesA;
	}
	
	public void setCategoriesA(Vector<String> arg){
		if(arg!=null){
			categoriesA=arg;
			CHANGED = true;
		}
	}
	
	public Vector<String> getCategoriesB(){
		return categoriesB;
	}
	
	public void setCategoriesB(Vector<String> arg){
		if(arg!=null){
			categoriesB=arg;
			CHANGED = true;
		}
	}
	
	public void addCategoryA(String s){
		if(s!=null && !s.trim().equals("")){
			categoriesA.add(s);
			CHANGED = true;
		}
	}
	public void addCategoryB(String s){
		if(s!=null && !s.trim().equals("")){
			categoriesB.add(s);
			CHANGED = true;
		}
	}
	
	public void deleteCategoryA(String s){
		if(categoriesA.size()>1){
			for(int i=0;i<categoriesA.size();i++){
				if(s.equals(categoriesA.elementAt(i))) categoriesA.remove(i); 
			}
			CHANGED = true;
		}
	}
	public void deleteCategoryB(String s){
		if(categoriesB.size()>1){
			for(int i=0;i<categoriesB.size();i++){
				if(s.equals(categoriesB.elementAt(i))) categoriesB.remove(i); 
			}
			CHANGED = true;
		}
	}
	
	public void setSortedTermClassKeysA(Vector<String> arg){
		if(arg!=null){
			sortedTermClassKeysA = arg;
			CHANGED = true;
		}
	}
	public void setSortedTermClassKeysB(Vector<String> arg){
		if(arg!=null){
			sortedTermClassKeysB = arg;
			CHANGED = true;
		}
	}
	
	public Vector<String> getSortedTermClassKeysA(){
		return sortedTermClassKeysA;
	}
	public Vector<String> getSortedTermClassKeysB(){
		return sortedTermClassKeysB;
	}
	
	/**
	 * Returns the vocabulary's name and identifier in the format "lang1 - lang2".
	 * @return vocabulary's name
	 */
	public String getName(){return languageA+" - "+languageB;}
	public String getNameA(){return languageA;}
	public String getNameB(){return languageB;}
	public Word[] getWords(){return vcb;}
	public void setName(String s1,String s2){
		languageA = s1;
		languageB = s2;
		name = languageA + " - " + languageB;
		CHANGED = true;
	}
	
	/**
	 * 
	 * Returns a Word-reference to vcb by the word's whole name.
	 * 
	 * @param query in format "lang1 - lang2"
	 * @return returns null if failed
	 */
	public Word getWordByName(String query){
		if(vcb!=null){
			for(int i=0;i<vcb.length;i++){
				if(vcb[i].getName().equals(query)) return vcb[i];
			}
		}
		return null;
	}
	
	/**
	 * @see #getWordByName(String query)
	 * @param query in format "lang2 - lang1"
	 * @return returns null if failed
	 */
	public Word getWordByNameInverse(String query){
		if(vcb!=null){
			for(int i=0;i<vcb.length;i++){
				if(vcb[i].getNameInverse().equals(query)) return vcb[i];
			}
		}
		return null;
	}
	
	public void setWords(Word[] wds){
		if(wds!=null){
			vcb = wds;
			CHANGED = true;
		}
	}
	

	protected void addWord(Word arg){
		Word[] tmp;
		if(vcb!=null){
			int l = vcb.length;
			tmp = new Word[l+1];
			for(int i=0;i<l;i++){
				tmp[i] = vcb[i];
			}
			tmp[l] = arg;
		}
		else{
			tmp = new Word[1];
			tmp[0] = arg;
		}
		vcb = tmp;
		CHANGED = true;
	}
	
	
	
	/**
	 * Deletes a Word.
	 * @param arg in the format "lang1 - lang2", not inverse 
	 */
	
	protected void delWord(String arg){
		if(vcb!=null){
			Word[] tmp = new Word[vcb.length-1];
			int j = 0;
			for(int i=0;i<vcb.length;i++){
				if(!arg.equals(vcb[i].getName())){
					tmp[j]=vcb[i];
					j++;
				}
			}
			vcb = tmp;
			CHANGED = true;
		}
	}
	
	/**
	 * Replaces a Word.
	 * 
	 * @param oldWord
	 * @param newWord
	 */
	
	protected void replaceWord(Word oldWord, Word newWord){
		if(vcb!=null){
			for(int i=0;i<vcb.length;i++){
				if(oldWord.getName().equals(vcb[i].getName())){
					vcb[i] = newWord;
					CHANGED = true;
					break;
				}
			}
		}
	}
	/**
	 * 
	 * Generates a String[] with all containing Word names.
	 * 
	 * @param inverse if true, second language is first
	 * @return String[] of all containing Word-names
	 */

	public String[] getWordList(boolean inverse){
		if(vcb!=null){
			String[] tmp_return = new String[vcb.length];
			for(int i=0;i<vcb.length;i++){
				if(inverse){
					tmp_return[i] = vcb[i].getTermB() + " - " + vcb[i].getTermA();
				}
				else{
					tmp_return[i] = vcb[i].getTermA() + " - " + vcb[i].getTermB();
				}
			}
			return tmp_return;
		}
		else return new String[0];
	}
	
	/**
	 * 
	 * Generates a alphabetically sorted String[] of all lections
	 * 
	 * @return String[] of lections
	 */
		
	public String[] getLections(){
		if(vcb!=null && vcb.length>0){
			ArrayList<String> tmp_vector = new ArrayList<String>();
			ArrayList<Integer> tmpVectorNumbers = new ArrayList<Integer>();
			for(int i=0;i<vcb.length;i++){
				String tmp_lec = vcb[i].getLection();
				try{
					Integer in = Integer.parseInt(tmp_lec);
					if(!tmpVectorNumbers.contains(in))tmpVectorNumbers.add(in);
				}
				catch(Exception e){
					if(!tmp_vector.contains(tmp_lec)) tmp_vector.add(tmp_lec);
				}
			}
			String[] tmp = new String[tmp_vector.size()];
			Collections.sort(tmp_vector,String.CASE_INSENSITIVE_ORDER);
			int size = tmp_vector.size();
			if(tmpVectorNumbers.size()>0){
				Collections.sort(tmpVectorNumbers);
				if(tmp_vector.size()>0){
					size = tmpVectorNumbers.size() + tmp_vector.size();
					tmp = new String[size];
					for(int i=0;i<tmpVectorNumbers.size();i++){
						tmp[i] = tmpVectorNumbers.get(i)+"";
					}
					for(int i=0;i<tmp_vector.size();i++){
						tmp[i+tmpVectorNumbers.size()] = tmp_vector.get(i)+"";
					}
				}
				else{
					size = tmpVectorNumbers.size();
					tmp = new String[size];
					for(int i=0;i<tmpVectorNumbers.size();i++){
						tmp[i] = tmpVectorNumbers.get(i)+"";
					}
				}
				
			}
			else{
				Collections.sort(tmp_vector,String.CASE_INSENSITIVE_ORDER);
				for(int i=0;i<size;i++){
					tmp[i] = tmp_vector.get(i).toString();
				}
			}
			return tmp;
		}
		return null;
	}
	
	/**
	 * 
	 * Generates a String containing all lection's names separated by ', '
	 * 
	 * @return String of lection's names or null
	 */
	
	public String getLectionsString(){
		String[] tmp = this.getLections();
		if(tmp!=null){
			String str = "";
			int ind = 1;
			for(String s : tmp){
				if(s.equals("~")) s = SET.getLanguage().getUnknown();
				if(ind<tmp.length)str = str + s + ", ";
				else str = str + s;
				ind++;
			}
			return str;
		}else return null;
	}
	
	/**
	 * Generates two Hashmaps of Words. Sorted by lection and alphabetically, the secound array is language inversed 
	 * sorted. The lections as keys are associated with a String[] of their Word's names. The keys are alph. sorted. 
	 * 
	 * @return null or 
	 */
	
	public HashMap<String,String[]> getSectionSortedAndIndexedHM(boolean inverse){
		if(!this.hasWords()) return null;
		HashMap<String,String[]> hm = new HashMap<String,String[]>();
		String[] tmp_lects = this.getLections();
		for(int i = 0;i<tmp_lects.length;i++){
			Vector<String> sectionCollector = new Vector<String>();
			//sort by section
			if(!inverse){
				for(int j=0;j<vcb.length;j++){
					if(vcb[j].getLection().equals(tmp_lects[i])){
						sectionCollector.add(vcb[j].getName());
					}
				}
			}
			else{
				for(int j=0;j<vcb.length;j++){
					if(vcb[j].getLection().equals(tmp_lects[i])){
						sectionCollector.add(vcb[j].getNameInverse());
					}
				}
			}
			sectionCollector.trimToSize();
			Collections.sort(sectionCollector, String.CASE_INSENSITIVE_ORDER);
			hm.put(tmp_lects[i],GuiTools.sortAndIndexVector(sectionCollector).toArray(new String[]{}));
		}
		return hm;
	}
	
	/**
	 * Checks if this Vocabulary hasWords
	 * @return true, if Vocabulary hasWords, else false
	 */
	
	public boolean hasWords(){
		return (vcb!=null && vcb.length>0);
	}
	
	public boolean hasWord(String pattern1,String pattern2){
		if(this.hasWords()){
			for(int i = 0;i<vcb.length;i++){
				Word tmp = vcb[i];
				if((tmp.getTermA().equals(pattern1)) && (tmp.getTermB().equals(pattern2))) return true;
			}
		}
		return false;
	}
	
	public boolean hasWord(String pattern){
		if(this.hasWords()){
			Word tmp;
			for(int i = 0;i<vcb.length;i++){
				tmp = vcb[i];
				if(tmp.getName().equals(pattern)) return true;
			}
		}
		return false;
	}
	
	public Vector<String> getUsedTermClassesA(){
		Vector<String> result;
		if(hasWords()){
			result =  new Vector<String>();
			for(Word w : vcb){
				if(!result.contains(w.getTermclassA())) result.add(w.getTermclassA());
			}
			return result;
		}
		else return null;
	}
	
	public Vector<String> getUsedTermClassesB(){
		Vector<String> result;
		if(hasWords()){
			result =  new Vector<String>();
			for(Word w : vcb){
				if(!result.contains(w.getTermclassB())) result.add(w.getTermclassB());
			}
			return result;
		}
		else return null;
	}
	
	public void deleteAllTermClasses(){
		tcsA = new HashMap<String,TermClass>();
		tcsB = new HashMap<String,TermClass>();
	}
	
	public void TCsAPut(String key, TermClass tc){
		if(key!=null && !key.equals("") && tc!=null){
			tcsA.put(key, tc);
			CHANGED = true;
		}
	}
	public void TCsBPut(String key, TermClass tc){
		if(key!=null && !key.equals("") && tc!=null){
			tcsB.put(key, tc);
			CHANGED = true;
		}
	}
	
	public void TCsAPutMeta(String tcName, String metaName, Vector<String> value){
		if(tcName!=null && !tcName.equals("") && metaName!=null && !metaName.equals("")){
			tcsA.get(tcName).putElement(metaName, value);
			CHANGED = true;
		}
	}
	public void TCsBPutMeta(String tcName, String metaName, Vector<String> value){
		if(tcName!=null && !tcName.equals("") && metaName!=null && !metaName.equals("")){
			tcsB.get(tcName).putElement(metaName, value);
			CHANGED = true;
		}
	}
	
	public void TCsASetPreFix(String tcName, String pfName, Vector<String> vals){
		if(tcName!=null && !tcName.equals("") && pfName!=null && !tcName.equals("")){
			tcsA.get(tcName).setPreFix(pfName, vals);
			CHANGED = true;
		}
	}
	public void TCsBSetPreFix(String tcName, String pfName, Vector<String> vals){
		if(tcName!=null && !tcName.equals("") && pfName!=null && !tcName.equals("")){
			tcsB.get(tcName).setPreFix(pfName, vals);
			CHANGED = true;
		}
	}
	
	public void TCsASetSortedKeys(String tcName, Vector<String> vals){
		if(tcName!=null && !tcName.equals("")){
			tcsA.get(tcName).setSortedKeys(vals);
			CHANGED = true;
		}
	}
	public void TCsBSetSortedKeys(String tcName, Vector<String> vals){
		if(tcName!=null && !tcName.equals("")){
			tcsB.get(tcName).setSortedKeys(vals);
			CHANGED = true;
		}
	}
			    
}//VOCABULARY-class